package calculator;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Calculator
{
	private Stack			stack;
	// Regulaerer Ausdruck fuer binaere operatorn
	private final String	binaryOperatorsRegExpression	= "/|-|\\+|\\*|\\^|max|min";

	// Regulaerer Ausdruck fuer unaere operatorn
	private final String	unaryOperatorsRegExpression		= "sqrt|ceil|floor|sin|cos|abs|log";

	// Regulaerer Ausdruck fuer zahlen
	private final String	numbersRegExpression			= "-?[0-9]+(\\.[0-9]+)?";

	public Calculator()
	{
		this.stack = new Stack();
	}

	public static void main(String[] args) throws IOException
	{
		Calculator calculator = new Calculator();

		String upn_expr = "26.0 3 1 / +";
		// System.out.println("Hi! Ich bin der Rechnikus, wenn ich dir auf den Sack gehe, schreib 'halt maul'!");
		// while (true)
		// {
		//
		// System.out.print("Was soll ich diesmal ausrechnen?  ");
		// String upn_expr = calculator.readIn();
		//
		// if (upn_expr.equalsIgnoreCase("halt maul"))
		// {
		// System.out
		// .println("Das war schoen! Viel Erfolg in der naechsten Matheklausur! Bye! :)");
		// break;
		// }

		double erg = calculator.calculate_upn(upn_expr);
		System.out.println("Das war doch simpel.. :) [" + upn_expr + "] = " + erg);
		// }

	}

	private boolean isNumber(String word)
	{
		return word.matches(this.numbersRegExpression); // muster fuer zahlen check
	}

	private boolean isBinaryOperator(String word)
	{
		return word.matches(this.binaryOperatorsRegExpression); // muster fuer zahlen check
	}

	private boolean isUnaryOperator(String word)
	{
		return word.matches(this.unaryOperatorsRegExpression);
	}

	private double calculate_upn(String upn_expr)

	{
		StringTokenizer tok = new StringTokenizer(upn_expr, " ");
		while (tok.hasMoreTokens())
		{
			String nextWord = tok.nextToken();

			if (isNumber(nextWord))
			{
				stack.push(nextWord);

			} else if (isBinaryOperator(nextWord))
			{

				String elem1 = stack.pop();
				String elem2 = stack.pop();
				double result = 0;

				if (nextWord.equals("+"))
				{
					result = Double.parseDouble(elem1) + Double.parseDouble(elem2);
				}

				else if (nextWord.equals("-"))
				{
					result = Double.parseDouble(elem2) - Double.parseDouble(elem1);
				}

				else if (nextWord.equals("*"))
				{
					result = Double.parseDouble(elem1) * Double.parseDouble(elem2);
				}

				else if (nextWord.equals("/"))
				{
					result = Double.parseDouble(elem2) / Double.parseDouble(elem1);
				}

				else if (nextWord.equals("^"))
				{
					result = Math.pow(Double.parseDouble(elem2), Double.parseDouble(elem1));
				}

				else if (nextWord.equals("max"))
				{
					result = Math.max(Double.parseDouble(elem1), Double.parseDouble(elem2));
				}

				else if (nextWord.equals("min"))
				{
					result = Math.min(Double.parseDouble(elem1), Double.parseDouble(elem2));
				}

				stack.push(result + "");

			} else if (isUnaryOperator(nextWord))
			{
				String elem1 = stack.pop();
				double result = 0;
				if (nextWord.equals("sqrt"))
				{
					result = Math.sqrt(Double.parseDouble(elem1));

				}
				if (nextWord.equals("ceil"))
				{
					result = Math.ceil(Double.parseDouble(elem1));

				}

				if (nextWord.equals("floor"))
				{
					result = Math.floor(Double.parseDouble(elem1));

				}

				if (nextWord.equals("sin"))
				{
					result = Math.sin(Double.parseDouble(elem1));

				}
				if (nextWord.equals("cos"))
				{
					result = Math.cos(Double.parseDouble(elem1));

				}
				if (nextWord.equals("abs"))
				{
					result = Math.abs(Double.parseDouble(elem1));

				}

				if (nextWord.equals("log"))
				{
					result = Math.log(Double.parseDouble(elem1));

				}

				stack.push(result + "");
			}
		}
		return Double.parseDouble(stack.pop());
	}

	@SuppressWarnings("unused")
	private String readIn() throws IOException
	{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String read = br.readLine();
		return read;
	}

}